#include "gt911.h"
#include "stdlib.h"
#include "usart1.h"
#include "string.h"
#include "i2c.h"
#include "tim6.h"
#include "nt35510.h"
#include "draw.h"

extern uint16_t LCD_X_LENGTH ;
extern uint16_t LCD_Y_LENGTH ;
extern uint32_t temp_x;
extern uint32_t temp_y;
touch_t touch_info = {0, 0, 0, 0, 0};

const uint8_t CTP_CFG_GT911[] =  {
    0x00,0x20,0x03,0xE0,0x01,0x05,0x0D,0x10,0x01,0x18,
    0x28,0x0F,0x50,0x32,0x03,0x05,0x00,0x00,0x00,0x00,
    0x11,0x11,0x05,0x18,0x1A,0x1E,0x14,0x88,0x29,0x0A,
    0x52,0x50,0x40,0x04,0x00,0x00,0x00,0x1A,0x32,0x1C,
    0x00,0x01,0x00,0x0F,0x00,0x2A,0xFF,0x7F,0x00,0x50,
    0x32,0x3C,0x64,0x94,0xD5,0x02,0x07,0x00,0x00,0x04,
    0x9F,0x3F,0x00,0x90,0x46,0x00,0x84,0x4D,0x00,0x79,
    0x55,0x00,0x6D,0x5F,0x00,0x6D,0x00,0x00,0x00,0x00,
    0xF0,0x4A,0x3A,0xFF,0xFF,0x27,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,0x10,
    0x12,0x14,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    0xFF,0xFF,0x22,0x21,0x20,0x1F,0x1E,0x1D,0x1C,0x18,
    0x16,0x12,0x10,0x0F,0x08,0x06,0x04,0x02,0x00,0xFF,
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    0xFF,0xFF,0xFF,0xFF,0x17,0x01
};  //0x53
TOUCH_IC touchIC = GT911;	

const TOUCH_PARAM_TypeDef touch_param[2] = 
{
    /* GT917S,4.3寸屏 */
    {
        .max_width = 480,
        .max_height = 800,
        .config_reg_addr = 0x8050,
    },
    
    /* GT911,4.3寸屏 */
    {
        .max_width = 480,
        .max_height = 800,
        .config_reg_addr = 0x8047,
    },
};
//初始化触摸屏
int32_t gt911_init(void)
{
    int32_t ret = -1;
    int32_t i = 0;
    uint16_t check_sum = 0;
    int32_t retry = 0;
    const uint8_t* cfg_info;
    uint8_t cfg_info_len;
	uint8_t* config;
    uint8_t cfg_num =0 ;		//需要配置的寄存器个数
    //初始化触摸屏GPIO
    I2C_Touch_Init();

    ret = gt911_init_test();
    if (ret < 0)
    {
        printf("I2C communication ERROR!");
		return ret;
    } 
    //获取触摸IC的型号
    GTP_Read_Version(); 
    config = (uint8_t *)malloc (GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);

	config[0] = GTP_REG_CONFIG_DATA >> 8;
	config[1] = GTP_REG_CONFIG_DATA & 0xff;

    cfg_info =  CTP_CFG_GT911; //指向寄存器配置
	cfg_info_len = CFG_GROUP_LEN(CTP_CFG_GT911);//计算配置表的大小

    memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
    memcpy(&config[GTP_ADDR_LENGTH], cfg_info, cfg_info_len);
    cfg_num = cfg_info_len;
		
    /*根据LCD的扫描方向设置分辨率*/
    config[GTP_ADDR_LENGTH+1] = LCD_X_LENGTH & 0xFF;
    config[GTP_ADDR_LENGTH+2] = LCD_X_LENGTH >> 8;
    config[GTP_ADDR_LENGTH+3] = LCD_Y_LENGTH & 0xFF;
    config[GTP_ADDR_LENGTH+4] = LCD_Y_LENGTH >> 8;
    check_sum = 0;
    for (i = GTP_ADDR_LENGTH; i < cfg_num; i++)
    {
        check_sum += (config[i] & 0xFF);
    }
    config[ cfg_num ] = (~(check_sum & 0xFF)) + 1; 	//checksum
    config[ cfg_num + 1 ] =  1; 						//refresh 配置更新标志
    //写入配置信息
    for (retry = 0; retry < 5; retry++)
    {
        ret = GTP_I2C_Write(GTP_ADDRESS, config , cfg_num + GTP_ADDR_LENGTH+2);
        if (ret > 0)
        {
            break;
        }
    }
    tim6_delay_ms(5);
	
    return 0;
}

#if 1
//版本号
int32_t GTP_Read_Version(void)
{
    int32_t ret = -1;
    uint8_t buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff};    //寄存器地址

    ret = GTP_I2C_Read(GTP_ADDRESS, buf, sizeof(buf));
    if (ret < 0)
    {
        printf("GTP read version failed");
        return ret;
    }
    if (buf[2] == '5')
    {
        printf("IC1 Version: %c%c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
				
        //GT5688芯片
        if(buf[2] == '5' && buf[3] == '6' && buf[4] == '8'&& buf[5] == '8')
            touchIC = GT5688;
    }        
    else if (buf[5] == 0x00)
    {
        printf("IC2 Version: %c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[7], buf[6]);
        //GT911芯片
        if(buf[2] == '9' && buf[3] == '1' && buf[4] == '1')
        {
            touchIC = GT911;
        }
    }
    else if (buf[5] == '7')
    {
        printf("IC3 Version: %c%c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
				
        //GT9147芯片
        if(buf[2] == '9' && buf[3] == '1' && buf[4] == '4' && buf[5] == '7')
            touchIC = GT9147;
		}
    else
    {
        printf("IC3 Version: %c%c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
        
        //GT9157芯片
        if(buf[2] == '9' && buf[3] == '1' && buf[4] == '5' && buf[5] == '7')
            touchIC = GT9157;
	}
    return ret;
}

#endif
//测试初始化是否正确
int8_t gt911_init_test(void)
{
    uint8_t test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
    uint8_t retry = 0;
    int8_t ret = -1;

    while(retry++ < 5)
    {
        ret = GTP_I2C_Read(GTP_ADDRESS, test, 3);
        if (ret > 0)
            break;
        
        printf("GTP i2c test failed time %d.",retry);
    }
    return ret;
}

/**
  * @brief   从IIC设备中读取数据
  * @param
  *		@arg client_addr:设备地址
  *		@arg  buf[0~1]: 读取数据寄存器的起始地址
  *		@arg buf[2~len-1]: 存储读出来数据的缓冲buffer
  *		@arg len:    GTP_ADDR_LENGTH + read bytes count（寄存器地址长度+读取的数据字节数）
  * @retval  i2c_msgs传输结构体的个数，2为成功，其它为失败
  */
int32_t GTP_I2C_Read(uint8_t client_addr, uint8_t *buf, int32_t len)
{
    struct i2c_msg msgs[2];
    int32_t ret = -1;
    int32_t retries = 0;

    /*一个读数据的过程可以分为两个传输过程:
     * 1. IIC  写入 要读取的寄存器地址
     * 2. IIC  读取  数据
     */

    msgs[0].flags = !I2C_M_RD;			      //写入
    msgs[0].addr  = client_addr;			  //IIC设备地址
    msgs[0].len   = GTP_ADDR_LENGTH;	      //寄存器地址为2字节(即写入两字节的数据)
    msgs[0].buf   = &buf[0];				  //buf[0~1]存储的是要读取的寄存器地址
    
    msgs[1].flags = I2C_M_RD;				  //读取
    msgs[1].addr  = client_addr;			  //IIC设备地址
    msgs[1].len   = len - GTP_ADDR_LENGTH;	  //要读取的数据长度
    msgs[1].buf   = &buf[GTP_ADDR_LENGTH];	  //buf[GTP_ADDR_LENGTH]之后的缓冲区存储读出的数据

    while(retries < 5)
    {
        ret = I2C_Transfer( msgs, 2);		  //调用IIC数据传输过程函数，有2个传输过程
        
        if(ret == 2)break;
        retries++;
    }
    if((retries >= 5))
    {
        printf("I2C Read: 0x%04X, %d bytes failed, errcode: %d! Process reset.", (((uint16_t)(buf[0] << 8)) | buf[1]), len-2, ret);
    }
    return ret;
}
/**
  * @brief   使用IIC进行数据传输
  * @param
  *		@arg i2c_msg:数据传输结构体
  *		@arg num:数据传输结构体的个数
  * @retval  正常完成的传输结构个数，若不正常，返回0xff
  */
int I2C_Transfer( struct i2c_msg *msgs,int num)
{
	int im = 0;
	int ret = 0;
	for (im = 0; im != num; im++)
	{
		if ((msgs[im].flags & I2C_M_RD))										    //根据flag判断是读数据还是写数据
		{
			ret = I2C_ReadBytes(msgs[im].addr, msgs[im].buf, msgs[im].len);		//IIC读取数据
            
		} else
		{
			ret = I2C_WriteBytes(msgs[im].addr,  msgs[im].buf, msgs[im].len);	//IIC写入数据
         
		}
	}

	if(ret)
		return ret;

	return im;  //正常完成的传输结构个数
}

/**
  * @brief   向IIC设备写入数据
  * @param
  *		@arg client_addr:设备地址
  *		@arg  buf[0~1]: 要写入的数据寄存器的起始地址
  *		@arg buf[2~len-1]: 要写入的数据
  *		@arg len:    GTP_ADDR_LENGTH + write bytes count（寄存器地址长度+写入的数据字节数）
  * @retval  i2c_msgs传输结构体的个数，1为成功，其它为失败
  */
int32_t GTP_I2C_Write(uint8_t client_addr,uint8_t *buf,int32_t len)
{
    struct i2c_msg msg;
    int32_t ret = -1;
    int32_t retries = 0;
    /*一个写数据的过程只需要一个传输过程:
     * 1. IIC连续 写入 数据寄存器地址及数据
     * */
    msg.flags = !I2C_M_RD;			//写入
    msg.addr  = client_addr;			//从设备地址
    msg.len   = len;							//长度直接等于(寄存器地址长度+写入的数据字节数)
    msg.buf   = buf;						//直接连续写入缓冲区中的数据(包括了寄存器地址)

    while(retries < 5)
    {
        ret = I2C_Transfer(&msg, 1);	//调用IIC数据传输过程函数，1个传输过程
        if (ret == 1)break;
        retries++;
    }
    if((retries >= 5))
    {
        printf("I2C Write: 0x%04X, %d bytes failed, errcode: %d! Process reset.", (((uint16_t)(buf[0] << 8)) | buf[1]), len-2, ret);
    }
    return ret;
}

//获取触摸屏相关配置信息
int32_t GTP_Get_Info(void)
{
    uint8_t opr_buf[10] = {0};
    int32_t ret = 0;

    uint16_t abs_x_max = GTP_MAX_WIDTH;
    uint16_t abs_y_max = GTP_MAX_HEIGHT;
    uint8_t int_trigger_type = GTP_INT_TRIGGER;
        
    opr_buf[0] = (uint8_t)((GTP_REG_CONFIG_DATA+1) >> 8);
    opr_buf[1] = (uint8_t)((GTP_REG_CONFIG_DATA+1) & 0xFF);
    
    ret = GTP_I2C_Read(GTP_ADDRESS, opr_buf, 10);
    if (ret < 0)
    {
        return 0;
    }
    
    abs_x_max = (opr_buf[3] << 8) + opr_buf[2];
    abs_y_max = (opr_buf[5] << 8) + opr_buf[4];
		printf("RES");   
		//GTP_DEBUG_ARRAY(&opr_buf[0],10);

    opr_buf[0] = (uint8_t)((GTP_REG_CONFIG_DATA+6) >> 8);
    opr_buf[1] = (uint8_t)((GTP_REG_CONFIG_DATA+6) & 0xFF);
    ret = GTP_I2C_Read(GTP_ADDRESS, opr_buf, 3);
    if (ret < 0)
    {
        return 0;
    }
    int_trigger_type = opr_buf[2] & 0x03;
    
    printf("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
            abs_x_max,abs_y_max,int_trigger_type);
    
    return 1;    
}

/**
  * @brief   触屏处理函数，轮询或者在触摸中断调用
  * @param 无
  * @retval 无
  */
void Goodix_TS_Work_Func(void)
{
        uint8_t  end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0};
        uint8_t  point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1]={GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF};
        uint8_t  touch_num = 0;
        uint8_t  finger = 0;
        static uint16_t pre_touch = 0;
        static uint8_t pre_id[GTP_MAX_TOUCH] = {0};

        uint8_t client_addr=GTP_ADDRESS;
        uint8_t* coor_data = NULL;
        int32_t input_x = 0;
        int32_t input_y = 0;
        int32_t input_w = 0;
        uint8_t id = 0;
    
        int32_t i  = 0;
        int32_t ret = -1;
                
        int32_t	tempx=0;
        int32_t	tempy=0;

        ret = GTP_I2C_Read(client_addr, point_data, 12);//10字节寄存器加2字节地址
        if (ret < 0)
        {
            printf("I2C transfer error. errno:%d\r\n ", ret);
            return;
        }
        
        finger = point_data[GTP_ADDR_LENGTH];//状态寄存器数据

        if (finger == 0x00)		//没有数据，退出
        {
            return;
        }

        if((finger & 0x80) == 0)//判断buffer status位
        {
            goto exit_work_func;//坐标未就绪，数据无效
        }

        touch_num = finger & 0x0f;//坐标点数
        if (touch_num > GTP_MAX_TOUCH)
        {
            goto exit_work_func;//大于最大支持点数，错误退出
        }
        touch_info.flag = 1;
        if (touch_num > 1)//不止一个点
        {
            uint8_t buf[8 * GTP_MAX_TOUCH] = {(GTP_READ_COOR_ADDR + 10) >> 8, (GTP_READ_COOR_ADDR + 10) & 0xff};
            ret = GTP_I2C_Read(client_addr, buf, 2 + 8 * (touch_num - 1));
            memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));			//复制其余点数的数据到point_data
        }

        if (pre_touch>touch_num)				         //pre_touch>touch_num,表示有的点释放了
        {
            for (i = 0; i < pre_touch; i++)				 //一个点一个点处理
            {
                uint8_t j;
                for(j=0; j<touch_num; j++)
                {
                    coor_data = &point_data[j * 8 + 3];
                    id = coor_data[0] & 0x0F;			  //track id
                    if(pre_id[i] == id)
                        break;

                    if(j >= touch_num-1)				  //遍历当前所有id都找不到pre_id[i]，表示已释放
                    {
                        GTP_Touch_Up( pre_id[i]);
                    }
                }
        }
        }


        if (touch_num)
        {
            for (i = 0; i < touch_num; i++)			 //一个点一个点处理
            {
                coor_data = &point_data[i * 8 + 3];

                id = coor_data[0] & 0x0F;			  //track id
                pre_id[i] = id;

                input_x  = coor_data[1] | (coor_data[2] << 8);	//x坐标
                input_y  = coor_data[3] | (coor_data[4] << 8);	//y坐标
                input_w  = coor_data[5] | (coor_data[6] << 8);	//size
                {

    /*扫描模式
                模式0                   模式1                     模式2                     模式3       
        -------------------     -------------------      -------------------       -------------------
        | 0--->x++        |     |                 |      |                 |       |       y++ <---0 |
        | |               |     |                 |      |                 |       |               | |
        | y++             |     |                 |      |                 |       |             x++ |
        |                 |     |    MAX:         |      |    MAX:         |       |    MAX:         |
        |   MAX:          |     |     x = 797     |      |     x = 477     |       |     x = 797     |
        |    x = 478      |     |     y = 477     |      |     y = 797     |       |     y = 477     |
        |    y = 798      |     | x++             |      |             y++ |       |                 |
        |                 |     | |               |      |               | |       |                 |
        |                 |     | 0--->y++        |      |       x++ <---0 |       |                 |
        -------------------     -------------------      -------------------       -------------------
        |       4.3       |     |       4.3       |      |       4.3       |       |       4.3       |
        -------------------     -------------------      -------------------       -------------------
    */
                
                    /*根据扫描模式更正X/Y起始方向*/
                    switch(SCAN_MODE)
                    {
                        case 0:
                        //在默认不覆盖触摸芯片参数下，触摸得出坐标方向与此屏幕程序方向3坐标一致。
                            break;

                        case 1:
                            tempx = input_x + 6;
                            tempy = input_y + 52;
                            input_x = (LCD_X_LENGTH-tempy);
                            input_y = 473 - (LCD_Y_LENGTH-tempx);
                            break;

                        case 2:
                            tempx = input_x + 2;
                            tempy = input_y + 52;
                            input_y = LCD_X_LENGTH-tempy;
                            input_x = LCD_Y_LENGTH-tempx;
                            break;

                        case 3:
                            tempx = input_x + 2;
                            tempy = input_y + 53;
                            input_x = 796 - (LCD_X_LENGTH-tempy);
                            input_y = (LCD_Y_LENGTH-tempx);
                            break;

                        default:
                            break;
                    }
                    GTP_Touch_Down( id, input_x, input_y, input_w);//数据处理
                }
            }
        }
        else if (pre_touch)		//touch_ num=0 且pre_touch！=0
        {
            for(i=0;i<pre_touch;i++)
            {
                GTP_Touch_Up(pre_id[i]);
            }
        }

        pre_touch = touch_num;

    exit_work_func:
        ret = GTP_I2C_Write(client_addr, end_cmd, 3);
        if (ret < 0)
        {
            printf("I2C write end_cmd error!");
        }
}

/**
  * @brief   用于处理或报告触屏检测到按下
  * @param
  *    @arg     id: 触摸顺序trackID
  *    @arg     x:  触摸的 x 坐标
  *    @arg     y:  触摸的 y 坐标
  *    @arg     w:  触摸的 大小
  * @retval 无
  */
/*用于记录连续触摸时(长按)的上一次触摸位置，负数值表示上一次无触摸按下*/
int16_t pre_x[GTP_MAX_TOUCH] ={-1,-1,-1,-1,-1};
int16_t pre_y[GTP_MAX_TOUCH] ={-1,-1,-1,-1,-1};

void GTP_Touch_Down(int32_t id,int32_t x,int32_t y,int32_t w)
{

	/*取x、y初始值大于屏幕像素值*/
    printf("ID:%d, X:%d, Y:%d, W:%d\r\n", id, x, y, w);
    touch_info.id = id;
    touch_info.x = x - 2;
    touch_info.y = y - 2;
}

/**
  * @brief   用于处理或报告触屏释放
  * @param 释放点的id号
  * @retval 无
  */
void GTP_Touch_Up( int32_t id)
{
    // LCD_Color_Init(0, 100, 0, 70, BLACK);      // 1    
    // LCD_Color_Init(0, 100, 70, 140, BLUE3);    // 2
    // LCD_Color_Init(0, 100, 140, 210, RED);     // 3
    // LCD_Color_Init(0, 100, 210, 280, GREEN);   // 4
    // LCD_Color_Init(0, 100, 280, 350, YELLOW);  // 5
    // LCD_Color_Init(0, 100, 350, 420, BRED);    // 6
    //LCD_Color_Init(101, 200, 421, 480, WHITE); 
    temp_x = 0;
    temp_y = 0;
    touch_info.x = 0;
    touch_info.y = 0;
    pre_x[id] = -1;
    pre_y[id] = -1;		
  
    printf("Touch id[%2d] release!", id);

}
